////////////////////////////////////////////////////////////////////////////////
//
//  Copyright 2010 galaxy.org
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//  http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

package org.galaxy.richflex.components
{
	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	
	import mx.controls.Alert;
	import mx.core.FlexGlobals;
	import mx.core.UIComponent;
	import mx.events.CloseEvent;
	import mx.events.SandboxMouseEvent;
	import mx.managers.PopUpManager;
	
	import org.galaxy.richflex.events.RichCloseEvent;
	import org.galaxy.richflex.skins.ResizableDialogSkin;
	
	import spark.components.TitleWindow;
	
	/**
	 * Event when dialog closes.
	 * 
	 * @eventType org.galaxy.richflex.events.RichCloseEvent.CLOSE_DIALOG
	 */
	[Event(name="closeDialog", type="org.galaxy.richflex.events.RichCloseEvent")]
	
	/**
	 * Dialog in application. Dialogs have no min/max buttons on the right top of the frame.
	 * If these buttons are need, <code>MDIWindow</code> should be used instead.
	 * <p>The resize part is depended on the code at 
	 * <a href="http://flexponential.com/2010/01/10/resizable-titlewindow-in-flex-4/" target="_blank">http://flexponential.com/2010/01/10/resizable-titlewindow-in-flex-4/</a>.
	 * Thanks for their work.</p>
	 * 
	 * @author Cheng Liang
	 * 
	 * @see org.galaxy.richflex.components.MDIWindow
	 * 
	 * @version 0.0.1 create 2010-9-8
	 */
	public class Dialog extends TitleWindow
	{
		
		// --------------------------------------------------------------------------
		//
		// Properties
		//
		// --------------------------------------------------------------------------
		
		// ------------------------------
		// resizable
		// ------------------------------
		
		private var _resizable : Boolean = false;
		
		[Bindable("dialogResized")]
		/**
		 * @private
		 */
		public function set resizable(value : Boolean) : void
		{
			if(_resizable != value) {
				_resizable = value;
				if(value) {
					setStyle("skinClass", ResizableDialogSkin);
				}
				dispatchEvent(new Event("dialogResized"));
			}
		}
		
		/**
		 * Sets if this dialog is resizable.
		 * 
		 * @default false
		 */
		public function get resizable() : Boolean
		{
			return _resizable;
		}
		
		//----------------------------------
		//  resizeHandler
		//---------------------------------- 
		
		[SkinPart(required="false")]
		/**
		 * The skin part that defines the area where the user may drag to resize the window.
		 */
		public var resizeHandler : UIComponent;
		
		private var clickOffset : Point;
		
		private var prevWidth : Number;
		private var prevHeight : Number;
		
		// --------------------------------------------------------------------------
		//
		// Constructor
		//
		// --------------------------------------------------------------------------
		
		public function Dialog()
		{
			super();
			
			this.width = 400;
			this.height = 300;
			
			addEventListener(CloseEvent.CLOSE, close);
		}
		
		//--------------------------------------------------------------------------
		//
		//  Overridden functions
		//
		//--------------------------------------------------------------------------
		
		override protected function partAdded(partName:String, instance:Object) : void
		{
			super.partAdded(partName, instance);
			
			if (instance == resizeHandler) {
				resizeHandler.addEventListener(MouseEvent.MOUSE_DOWN, onResizeHandlerMouseDown);
			}
		}
		
		override protected function partRemoved(partName:String, instance:Object):void
		{
			if (instance == resizeHandler) {
				resizeHandler.removeEventListener(MouseEvent.MOUSE_DOWN, onResizeHandlerMouseDown);
			}
			
			super.partRemoved(partName, instance);
		}
		
		//--------------------------------------------------------------------------
		//
		//  Event handlers
		//
		//--------------------------------------------------------------------------
		
		/**
		 * @private
		 */
		protected function onResizeHandlerMouseDown(event : MouseEvent) : void
		{
			if (enabled && isPopUp && !clickOffset) {        
				clickOffset = new Point(event.stageX, event.stageY);
				prevWidth = width;
				prevHeight = height;
				
				var sbRoot:DisplayObject = systemManager.getSandboxRoot();
				sbRoot.addEventListener(MouseEvent.MOUSE_MOVE, onResizeHandlerMouseMove, true);
				sbRoot.addEventListener(MouseEvent.MOUSE_UP, onResizeHandlerMouseUp, true);
				sbRoot.addEventListener(SandboxMouseEvent.MOUSE_UP_SOMEWHERE, onResizeHandlerMouseUp)
			}
		}
		
		/**
		 * @private
		 */
		protected function onResizeHandlerMouseMove(event : MouseEvent) : void
		{
			// during a resize, only the TitleWindow should get mouse move events
			// we don't check the target since this is on the systemManager and the target
			// changes a lot -- but this listener only exists during a resize.
			event.stopImmediatePropagation();
			
			if(!clickOffset) {
				return;
			}
			
			width = prevWidth + (event.stageX - clickOffset.x);
			height = prevHeight + (event.stageY - clickOffset.y);
			event.updateAfterEvent();
		}
		
		/**
		 * @private
		 */
		protected function onResizeHandlerMouseUp(event : Event) : void {
			clickOffset = null;
			prevWidth = NaN;
			prevHeight = NaN;
			
			var sbRoot:DisplayObject = systemManager.getSandboxRoot();
			
			sbRoot.removeEventListener(MouseEvent.MOUSE_MOVE, onResizeHandlerMouseMove, true);
			sbRoot.removeEventListener(MouseEvent.MOUSE_UP, onResizeHandlerMouseUp, true);
			sbRoot.removeEventListener(SandboxMouseEvent.MOUSE_UP_SOMEWHERE, onResizeHandlerMouseUp);
		}
		
		// --------------------------------------------------------------------------
		//
		// Other functions
		//
		// --------------------------------------------------------------------------
		
		/**
		 * Shows this dialog. The dialog will be shown at the center of parent component.
		 * If parent is null, the dialog will be shown at the center of this application.
		 * 
		 * @param parent parent component, default is null
		 * @param modal true if is modal, default is false
		 */
		public function show(parent : DisplayObject = null, modal : Boolean = false) : void
		{
			if(parent == null) {
				PopUpManager.addPopUp(this, DisplayObject(FlexGlobals.topLevelApplication), modal);
			} else {
				PopUpManager.addPopUp(this, parent, modal);
			}
			PopUpManager.centerPopUp(this);
		}
		
		/**
		 * Closes this dialog. If additional operations should be added when dialog closes,
		 * this function can be overridden. But <code>removeDialog()</code> need to be called
		 * in order to close dialog as default.
		 * 
		 * @param event close event type of <code>RichCloseEvent</code> which can be null
		 */
		public function close(event : CloseEvent = null) : void
		{
			var e : RichCloseEvent = new RichCloseEvent(RichCloseEvent.CLOSE_DIALOG);
			e.closeDetail = RichCloseEvent.CLOSE_CANCEL;
			dispatchEvent(e);
			removeDialog();
		}
		
		/**
		 * Remove dialog from stage. This should be called in close event handler or the dialog
		 * could not disappear. <strong>Note that this function does not dispatch event so
		 * it is useful for overridden close event handler.</strong>
		 */
		protected function removeDialog() : void
		{
			PopUpManager.removePopUp(this);
		}
		
	}
}